# -*- coding: utf-8 -*-
# Project : flacon
# File : inet.py
# (c) Alexander Sokolov sokoloff.a@gmail.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.


import sys, os

from PyQt4 import QtCore
from PyQt4 import QtNetwork
from PyQt4.QtCore import *
from PyQt4.QtNetwork import *

#from disc import *
from trackset import *
from track import *
import flacon
import errors
import settings

import re


#*******************************************************************
# CDDB & FreeDB downloader
# See http://www.freedb.org/en/download__miscellaneous.11.html
#*******************************************************************
class FreeDbDowloader(QObject):
    # Categories from http://freedb.freedb.org/~cddb/cddb.cgi?cmd=CDDB+LSCAT&hello=n+h+c+1&proto=6
    categories = [
#            'data',
            'folk',
            'jazz',
            'misc',
            'rock',
            'country',
            'blues',
            'newage',
            'reggae',
            'classical',
            'soundtrack',
        ]


   #****************************************************************
   #
   #****************************************************************
    def __init__(self, disc):
        QObject.__init__(self)
        self._disc = disc

        self._result = []
        self._requests = {}
        self._http = QHttp(self)

        self._serverHost= settings.settings.value("Inet/CDDBHost").toString()
        self._http.setHost(self._serverHost)

        self.connect(self._http, SIGNAL("done(bool)"), SIGNAL("done()"))
        self.connect(self._http, SIGNAL("requestFinished(int,bool)"), self._requestFinished)


   #****************************************************************
   #
   #****************************************************************
    @staticmethod
    def canDownload(disc):
        return disc.tracks().discId() != ''


   #****************************************************************
   #
   #****************************************************************
    def result(self):
        return self._result


   #****************************************************************
   #
   #****************************************************************
    def get(self):
        if not FreeDbDowloader.canDownload(self._disc):
            return

        self.emit(SIGNAL("started()"))
        discId = self._disc.tracks().discId()

        urlMask = "/~cddb/cddb.cgi?cmd=CDDB+READ+%%s+%s&hello=%s+%s+%s+%s&proto=6" % (
                discId,
                'anonimous',            # Hello user
                '127.0.0.1',            # Hello host
                'flacon',               # Hello client name
                flacon.FLACON_VERSION   # Hello client version
            )

        for category in self.categories:
            url = urlMask % category
            id = self._http.get(QString(url))
            self._requests[id] = (url, category)
            #print url
            self._http.close()


   #****************************************************************
   #
   #****************************************************************
    def _requestFinished(self, id, error):
        if not self._requests.has_key(id):
            return

        http = self._http

        # Network errors ..................................
        if error:
            raise errors.NetworkError(http.errorString())

        # HTTP errors .....................................
        resp = http.lastResponse()
        if resp.statusCode() != 200:
            http.abort()
            self.emit(SIGNAL("done()"))
            raise errors.NetworkError(QString('%1 %2').arg(resp.statusCode()).arg(resp.reasonPhrase()))

        lines = QString.fromLocal8Bit(http.readAll().data()).split("\n")

        statusLine = lines.takeFirst()
        status = statusLine.section(' ', 0, 0)

        # CDDB errors .....................................
        if status == '210': # OK
            self._parseLines(id, lines)

        elif status == '401': # No such CD entry in database, skip.
            return

        else: # Error
            http.abort()
            self.emit(SIGNAL("done()"))
            raise  errors.NetworkError(statusLine)


   #****************************************************************
   #
   #****************************************************************
    def _parseLines(self, id, lines):
        titles = []
        album = QString()
        artist = QString()
        year = QString()
        genre = QString()
        discId = QString()

        # Parse result :::::::::::::::::::::::::::::::::::::::::::::
        for line in lines:
            if len(line) == 0 or line.at(0) == QChar('#'):
                continue

            try:
                (name, value) = line.trimmed().split("=")
            except ValueError:
                continue

            if name.startsWith('TTITLE'):
                titles.append(value)

            if name.startsWith('DTITLE'):
                # The artist and disc title (in that order) separated by a "/" with a
                # single space on either side to separate it from the text.
                artist = value.section(' / ', 0, 0).trimmed()
                album = value.section(' / ', 1).trimmed()

            if name.startsWith('DYEAR'):
                year = value

            if name.startsWith('DGENRE'):
                genre = value

            if name.startsWith('DISCID'):
                discId = value.toUpper()



        # Create trackSet ::::::::::::::::::::::::::::::::::::::::::
        (url, category) = self._requests[id]
        tracks = TrackSet(url)
        tracks.setTitle(QString("CDDB %1 - %2 / %3").arg(category).arg(artist).arg(album ), False)
        tracks.setDiscId(discId)

        n = 1
        for title in titles:
            track = tracks.newTrack()

            if title.indexOf(' / ') > -1:
                # If the disc is a sampler and there are different artists for the
                # track titles, the track artist and the track title (in that order)
                # should be separated by a "/" with a single space on either side
                # to separate it from the text.
                track.setArtist(title.section(' / ', 0, 0).trimmed(), False)
                track.setTitle(title.section(' / ', 1).trimmed(), False)
            else:
                track.setArtist(artist, False)
                track.setTitle(title, False)

            track.setAlbum(album, False)
            track.setGenre(genre, False)
            track.setYear(year)
            track.setTrackNum(n)
            n+=1


        self._result.append(tracks)

